<?php
namespace App\Services\Etouch;

use App\Services\Array2XML;
use App\Services\Etouch\EtouchClientException;
use Log;

class EtouchClientOld
{
    protected $config;
    protected $sto;
    protected $pay;
    protected $pubkey;
    protected $privkey;

    function __construct()
    {
        $config = config('eorderinfo');
        $this->sto = config('shipping.eto.config');
        $this->pay = config('alipay-custom');
        $this->wxpay = config('wxpay-custom');
        $this->config = $config;
        $this->pubkey = $config['publicKey'];

    }



    public function push($order, $optType, $shipping_time)
    {
Log::info('旧版本推关');

        $batchNumbers = strtotime($shipping_time);

        // $batchNumbers = strtotime($order->add_time);
        $nowHour = date('H',$batchNumbers);
        $batchNumbers = date('Ymd',$batchNumbers);
        if($nowHour>=0 && $nowHour<12){
                $batchNumbers .= '1';
        }elseif($nowHour>=12 && $nowHour<24){
                $batchNumbers .= '2';
        }//end if()

        $xmlOrder['OrderHead'] = [
            'ecCode' => $this->config['ecCode'],//国检备案的电商企业代码
            'cbeCode' => $this->config['cbeCode'],//海关备案的电商企业代码
            'ecName' => $this->config['ecName'],//国检备案的电商企业名称
            'cbeName' => $this->config['cbeName'],//海关备案的电商企业名称
            'ecpCodeCiq' => $this->config['ecpCodeCiq'],//在国检备案的电商平台代码，如果一个电商有多个电商平台，则根据订单的商品出自哪个平台，在此填写哪个电商平台代码，如电商企业在国检没有备案电商平台，以电商代码代码代替
            'ecpCodeCus' => $this->config['ecpCodeCus'],//在海关备案的电商平台代码，如果一个电商有多个电商平台，则根据订单的商品出自哪个平台，在此填写哪个电商平台代码，如电商企业在海关没有备案电商平台，以电商代码代码代替
            'ecpNameCiq' => $this->config['ecpNameCiq'],//国检备案的电商平台名称
            'ecpNameCus' => $this->config['ecpNameCus'],//海关备案的电商平台名称,
            'orderNo' => $order->order_sn,//电商平台上生成的订单编号，唯一
            //'charge' => $order->order_price,//总费用 货值+运费+其它费用+进口行邮税=总费用，必填
            // 'charge' => $order->pay_price + $order->coupon_price + $order->discount_price,//总费用 货值+运费+其它费用+进口行邮税=总费用，必填
            'charge' => $order->pay_price + $order->coupon_price,//总费用 货值+运费+其它费用+进口行邮税=总费用，必填
            'goodsValue' => $order->order_price - $order->discount_price,// 货值 订单中商品的货值，即订单上所有商品总价之和 - 商品的折扣金额
            'freight' => '',//  非必填，运费 一般是指跨境的运费
            // 'other' => $order->coupon_price + $order->discount_price,//  非必填，其他费用 其他费
            'other' => $order->coupon_price,//  非必填，其他费用 其他费
            'tax' => $order->order_tariff_fee,// 非必填，申报时可以报关行补填
            'customer' => '',//  非必填 客户姓名 一般是指下订单的人
            'shipper' => $this->config['companyName'],//发货人名称
            'shipperAddress' => $this->config['address'],//发货人地址
            'shipperTelephone' => $this->config['phone'],//发货人电话
            'shipperCountryCiq' =>'156',//国检系统的发货人所在国编码（参考数据字典国检的国家代码）
            'shipperCountryCus' => '142',//海关系统的发货人所在国编码（参考数据字典海关的国家代码）
            'consignee' => $order->consignee,
            'consigneeProvince' => $order->province,//收货人省份
            'consigneeCity' => $order->city,//收货人城市
            'consigneeZone' => $order->district,//收货人区县
            'consigneeAddress' => $order->province.$order->city.$order->district.$order->address,//收货人地址
            'consigneeTelephone' => $order->mobile,//收货人电话
            'consigneeCountryCiq' => '156',//国检系统的收获人所在国编码（参考数据字典国检的国家代码）YES
            'consigneeCountryCus' => '142',//海关系统的收获人所在国编码（参考数据字典海关的国家代码）YES
            'idType' => $order->id_type,//1-身份证 2-军官证 3-护照 4-其他
            'idNumber' => $order->id_card,//根据证件类型填写相应的证件号码
            'ieType' => 'I',//I-进口  E-出口
            'stockFlag' => 2,//1-集货 2-备货
            //'batchNumbers' => 'ZYFT'.'20160311',//方便查询和报关行申报
            'batchNumbers' => 'ZYFT'.$batchNumbers,//方便查询和报关行申报
            'totalLogisticsNo' => '', //运单由物流企业承运，物流企业的总运单号
            'tradeCountryCiq' => '156',//进口是发货人国家的国检编码，出口是收货人国家的国检编码（参考数据字典国检的国家代码）
            'tradeCountryCus' => '142',//进口是发货人国家的海关编码，出口是收货人国家的海关编码（参考数据字典海关的国家代码）
            'agentCodeCiq' => '4101983436',//一般是报关行，或者有申报权限的电商或物流企业在国检备案的企业代码（不是自己报关的必填）
            'agentCodeCus' => '4101983436',//一般是报关行，或者有申报权限的电商或物流企业在海关备案的企业代码（不是自己报关的必填）
            'agentNameCiq' => '河南中启保税报关有限公司',//一般是报关行，或者有申报权限的电商或物流企业在国检备案的企业名称（不是自己报关的必填）
            'agentNameCus' => '河南中启保税报关有限公司',//一般是报关行，或者有申报权限的电商或物流企业在海关备案的企业名称（不是自己报关的必填）
            'packageTypeCiq' => '4M',//包装种类（参考数据字典的国检包装种类代码）
            'packageTypeCus' => '2',//包装种类（参考数据字典的海关包装种类代码）
            'modifyMark' => '1',//1-新增 2-修改 3-删除；一般为1
            'note' => '',//订单备注信息
        ];

        $weight = 0.00;
        $order_goods_number = 0;
        foreach ($order->orderGoods as $k => $goods) {

            $xmlOrder['OrderList'][] = [
                'itemNoCiq' => '', //国检备案商品编号
                'itemNoCus' => '',
                'goodsNo' => $goods->goods_sn,
                'shelfGoodsName' => $goods->goods_name,
                'goodsName' => '', //非必填，若不填，系统从上架品名反填
                'describe' => '', //商品描述
                'codeTs' => '', //商品的HS编码,即：商品名称及编码协调制度的国际公约（参考数据字典的hs编码）
                'ciqCode' => '', //商品的CIQ编码（参考数据字典的ciq编码）
                'goodsModel' => '', //规格型号
                'taxCode' => '', //商品的行邮税，按照这个进行收税
                // 'price' => $goods->shop_price, //商品成交的单价
                'price' => $goods->goods_real_price, //商品成交的单价
                'currencyCiq' => $goods->currencyCiq, //国检币制（参考数据字典的国检币制代码）
                'currencyCus' => $goods->currencyCus, //海关币制（参考数据字典的海关币制代码）
                'quantity' => $goods->buy_number, //商品成交数量
                //'priceTotal' => $order->order_price, //商品的成交单价X数量
                //'priceTotal' => $goods->goods_price * $goods->goods_number,
                'priceTotal' => $goods->goods_real_price * $goods->buy_number,
                'unitCiq' => $goods->unitCiq, //国检计量单位（参考数据字典的国检计量单位代码）
                'unitCus' => $goods->unitCus, //海关计量单位（参考数据字典的海关计量单位代码）
                //'discount' => $order->incentives_price, //商品的折扣优惠，折扣优惠不会参与计算入商品总价里面
                'discount' => '', //商品的折扣优惠，折扣优惠不会参与计算入商品总价里面
                'giftsFlag' => '', //N-不是 Y-是（赠品单价应该为0）
                'originCountryCiq' => $goods->originCountryCiq, //商品产地所在国（参考数据字典的国检国家代码）
                'originCountryCus' => $goods->originCountryCus, //商品产地所在国（参考数据字典的海关国家代码）
                'usage' => '', //1-种用或繁殖 2- 食用 3- 奶用 4- 观赏或演艺 5-伴侣 6-实验 7-药用 8-饲用 9-其他 10-介质土 A-食品包装材料 B-食品加工设备 C-食品添加剂 D-食品容器 E-食品洗涤剂 F-食品消毒剂
                'wasteMaterials' => '1', //1-正常 2-废品 5-旧品 9-其他
                'wrapTypeCiq' => '4M', //参考国检包装种类代码
                'wrapTypeCus' => '2', //参考海关包装种类代码
                'packNum' => '1', //件数与成交数量可以不一致，该件数指的是包装商品包装的件数

            ];
            $order_goods_number += $goods->buy_number;
            $weight +=$goods->buy_number*$goods->weight;
        }


        $paymentCode = '';          //海关备案的支付企业代码

        $paymentName = '';          //海关备案的支付企业类型

        if (isset($order->pay_type)) {

            switch ($order->pay_type) {

                case 'alipay':

                    $paymentCode = $this->pay['paymentCode'];
                    $paymentName = $this->pay['paymentName'];

                    break;

                case 'wxpay':

                    $paymentCode = $this->wxpay['paymentCode'];
                    $paymentName = $this->wxpay['paymentName'];

                    break;
            }
        }

        $xmlOrder['OrderPaymentLogistics'] = [
            'paymentCode' => $paymentCode, //海关备案的支付企业代码
            'paymentName' => $paymentName, //海关备案的支付企业类型
            'paymentType' => '', //A-全款S-商户款,X-行邮税
            'paymentNo' => $order->pay_num, //订单支付产生的支付交易号
            'logisticsCodeCiq' => $this->sto['logisticsCodeCiq'], //海关备案的物流企业代码
            'logisticsCodeCus' => $this->sto['logisticsCodeCus'], //海关备案的物流企业代码
            'logisticsNameCiq' => $this->sto['name'], //海关备案的物流企业名称
            'logisticsNameCus' => $this->sto['name'], //海关备案的物流企业名称
            'totalLogisticsNo' => '', //$goods->totalLogisticsNo, //运单由物流企业承运，物流企业的总运单号
            'subLogisticsNo' => '', //当时是为了区分这三层运单的情形(即有总运单、分运单、面单)，实际中一般只有总运单和运单，是两层结构。所以物流商一般只需指定总运单号和运单号即可。
            //'logisticsNo' => '', //物流运单号
            'logisticsNo' => @$order->shipping_num, //物流运单号
            'trackNo' => '', //一般是航班号，是描述字段。
            'trackStatus' => '', //是物流跟踪号的状态描述，也是描述字段。不参与E贸易流程。初始化后不会再变。有4个：A-承运,R-运抵,S-签收,C-取消
            'crossFreight' => '', //境外运输的费用
            'supportValue' => '', //针对一个运单里的所有商品的报价金额
            'weight' => number_format($weight,2),//（精度两位） $goods->goods_weight, //整个包裹的重量,单位（kg）
            'netWeight' => '', //商品的重量，除掉包装箱的重量,单位（kg）
            'quantity' => $order_goods_number, //一个运单就是一个包裹，不存在多个包裹。是商品数。
            'deliveryWay' => '', //通关标准的交货方式术语（参考数据字典交货方式代码）
            'transportationWay' => $goods->transportationWay, //国检运输方式（参考数据字典运输方式代码）
            'shipCode' => $goods->shipCode, //国检运输工具（参考数据字典运输工具代码）
            'shipName' => '', //非必填，一般填公路运输、铁路运输的多。
            'destinationPort' => '', //出口指定指运港，进口指定国外的装运港（参考数据字典的装运港和指运港代码）
        ];


        $xml = Array2XML::createXML('Order', $xmlOrder)->saveXML();
        //echo $xml;exit();
        Log::info('推送订单['.$order->order_id.']到海关,未加密报文:'.$xml);


        $signedDataInfo = $this->encrypt($xml);

        $request = [
            'PubInfo' => [
                'Version' => ['@value' => $this->config['Version']],//Webservice接口版本
                'CompanyCode' => $this->config['companyCode'],//发送企业编号
                'Key' => $this->config['companyKey'],//发送企业Key；用于身份识别
                'MsgType' => 'O',//O-订单；W-运单；T-妥投；S-账册
                //'OptType' => 1,//1-新增；2-修改
                'OptType' => $optType,//1-新增；2-修改
                'Signature' => $this->md5($signedDataInfo),//验证加密报文是否一致  数据签名细节：已加密订单信息字符串以“UTF-8”编码转成字节数组后经MD5摘要算法得出32位摘要签名。
                'CreatTime' => date('Y-m-d H:i:s'),//单据生成日期
            ],
            'DataInfo' => [
                '@cdata' => $signedDataInfo
            ]
        ];

        $requestXml = Array2XML::createXML('Root', $request)->saveXML();
        Log::info('推送订单['.$order->order_id.']到海关,加密报文:'.$requestXml);

        return $this->makeRequest($this->config['url'], ['xml' => $requestXml], $order->order_id);


    }

    /**加密**/
    public function encrypt($data)
    {
        if (empty($data)) {
            return null;
        }
        $pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($this->pubkey, 64, "\n") . "-----END PUBLIC KEY-----\n";
        $key = openssl_pkey_get_public($pem);
        $resultb = "";
        $dataArray = str_split($data, 117);
        foreach ($dataArray as $d) {
            if (openssl_public_encrypt($d, $encrypted, $key)) {
                $resultb .= $encrypted;
            } else return null;
        }
        return base64_encode($resultb);
    }

    /**解密**/
    public function decrypt($data)
    {
        $pem = "-----BEGIN PRIVATE KEY-----\n" . chunk_split($this->privkey, 64, "\n") . "-----END PRIVATE KEY-----\n";
        $key = openssl_pkey_get_private($pem);
        $resultb = "";
        $dataArray = str_split(base64_decode($data), 128);
        foreach ($dataArray as $d) {
            if (openssl_private_decrypt($d, $encrypted, $key)) {
                $resultb .= $encrypted;
            } else return null;
        }
        return $resultb;
    }


    /**数字签名**/

    public function md5($data)
    {

        $xt = md5($data);
//        $xtt = urlencode(base64_encode($xt)); //数字签名
        return $xt;
    }


    /**
     * POST 请求
     * @param string $url
     * @param array $param
     * @return string content
     */
    public function request($url, $param)
    {
        $strPOST = '';
        $oCurl = curl_init();
        if (stripos($url, "https://") !== FALSE) {
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($oCurl, CURLOPT_SSL_VERIFYHOST, false);
        }
        if (is_string($param)) {
            $strPOST = $param;
        } else {
            $aPOST = array();
            foreach ($param as $key => $val) {
                $aPOST[] = $key . "=" . urlencode($val);
            }
            $strPOST = join("&", $aPOST);
        }
        curl_setopt($oCurl, CURLOPT_URL, $url);
        curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($oCurl, CURLOPT_POST, true);
        curl_setopt($oCurl, CURLOPT_POSTFIELDS, $strPOST);
        $sContent = curl_exec($oCurl);
        $aStatus = curl_getinfo($oCurl);
        curl_close($oCurl);
        if (intval($aStatus["http_code"]) == 200) {
            return $sContent;
        } else {
            return false;
        }
    }


    /**
     * 构建请求
     * @param $data
     * @return mixed|string
     */
    private function makeRequest($url, $data, $order_id)
    {
        //print_r ($data);

        try {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            $response = curl_exec($ch);
           //echo $response;exit();

            Log::info('推送订单到海关,响应:报文'.$response);

        }catch (\Exception $e){


            //将推关失败的信息存入订单推关信息表
            $push_tarrif_status = 4;
            $this->pushTarrifService->updatePushTarrif($order_id, $push_tarrif_status, $e->getMessage());
            throw new EtouClientException($e->getMessage());
        }
        $repsonXmlObj = simplexml_load_string($response);
        //print_r ($repsonXmlObj);exit();

        if($repsonXmlObj->Status=='0'){


            return true;
        }
        else{
            //将推关失败的信息存入订单推关信息表
            $push_tarrif_status = 4;
            $this->pushTarrifService->updatePushTarrif($order_id, $push_tarrif_status, $repsonXmlObj->Detail);
            throw new EtouchClientException($repsonXmlObj->Detail);
        }



    }

}

//$str='RSA';
//$xml='';
////用法
//$rsa=new RSA();
////加密
//$rsa->encrypt($str);
////解密
//$rsa->encrypt($str);
//$rsa->md5($xml);